package show.lmm.spring_data_r2dbc.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import show.lmm.spring_data_r2dbc.core.DynamicDataSource;
import show.lmm.spring_data_r2dbc.core.entity.UserInfo;
import show.lmm.spring_data_r2dbc.mapper.UserRepository;

/**
 * 用户 service
 */
@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    private final DatabaseClient dbClient;

    public UserService(
            UserRepository userRepository,
            DatabaseClient dbClient) {
        this.userRepository = userRepository;
        this.dbClient = dbClient;
    }

    /**
     * 查询用户信息
     *
     * @param userId 用户id
     */
    public Mono<UserInfo> get(int userId) {
        return userRepository.findById(userId);
    }

    /**
     * 查询最大的用户id
     */
    public Mono<Integer> getMaxUserId() {
        return dbClient.sql("select max(user_id) user_id from user_info where status = 1")
                .fetch().one()
                .flatMap(result -> {
                    if (result.get("user_id") instanceof Integer v) {
                        return Mono.just(v);
                    }
                    return Mono.just(0);
                });
    }

    /**
     * 查询用户列表
     */
    public Flux<UserInfo> list(String dbName) {
        return dbClient.sql("select user_id,user_name from user_info where status = 1")
                .fetch().all()
                .flatMap(result -> {
                    UserInfo userInfo = new UserInfo();
                    if (result.get("user_id") instanceof Integer userId) {
                        userInfo.setUserId(userId);
                    }
                    if (result.get("user_name") instanceof String userName) {
                        userInfo.setUserName(userName);
                    }
                    return Mono.just(userInfo);
                })
                .contextWrite(context -> context.put(DynamicDataSource.CURRENT_DB_NAME, dbName));
    }

    /**
     * 新增用户
     *
     * @param userName 用户名
     */
    public Mono<Boolean> insert(String userName) {
        return dbClient.sql("insert into user_info(user_name) values(:userName)")
                .bind("userName", userName)
                .fetch().rowsUpdated().hasElement();
    }

    /**
     * 新增用户
     *
     * @param userId 用户id
     */
    public Mono<Boolean> delete(int userId) {
        return dbClient.sql("delete from user_info where user_id= :userId")
                .bind("userId", userId)
                .fetch().rowsUpdated().hasElement();
    }

    /**
     * 测试事务
     */
    @Transactional(rollbackFor = Exception.class)
    public Flux<UserInfo> testTransaction(String userName) {
        insert(userName);
        if (1 == 1) {
            throw new RuntimeException("test error");
        }
        return list("tenant1");
    }
}
